import types
from functools import wraps


# 类有__call\__、__get__方法就可以作为装饰器使用
class Profiled:
    def __init__(self, func):
        wraps(func)(self)
        self.ncalls = 0

    def __call__(self, *args, **kwargs): # 可以作为装饰器的关键就是call
        self.ncalls += 1
        return self.__wrapped__(*args, **kwargs)

    def __get__(self, instance, owner):  # __get__获取属性,获取实例的属性，并非self的属性
       # print(instance,owner)
        if instance is None:
            return self
        else:
            return types.MethodType(self, instance)  # type.MethodType() instance，self指向bar()这个方法


@Profiled
def add(x, y):
    return x + y


class Spam:
    @Profiled
    def bar(self, x):
        print(self, x)


if __name__ == '__main__':
    add(2, 3)
    s= Spam()
    s.bar(10) # s.bar(10)会走到__get__,且instance就指向s,bar作为方法被绑定
    # 相当于执行了Spam.bar.__get__(bar,s)=types.MethodType(bar,s)

    print(Spam.bar.ncalls)
    #print(s.ncalls)

